package gdufs.lkl.calculator;

import android.util.Log;

import java.text.DecimalFormat;
import java.util.Random;
import java.util.Stack;

// JEP 表达式解析库
import org.nfunk.jep.JEP;
import org.nfunk.jep.function.ArcCosine;
import org.nfunk.jep.function.ArcSine;
import org.nfunk.jep.function.ArcTangent;
import org.nfunk.jep.function.Cosine;
import org.nfunk.jep.function.PostfixMathCommand;
import org.nfunk.jep.function.Sine;
import org.nfunk.jep.function.Tangent;

/**
 * 通用计算引擎
 * 为基础计算器和科学计算器提供统一的计算逻辑
 */
public class CalculationEngine {
    private static final String TAG = "CalculationEngine";
    private static CalculationEngine instance;

    // JEP解析器实例
    private JEP jepRadian; // 弧度模式解析器
    private JEP jepDegree;  // 角度模式解析器

    // 计算引擎构造函数（私有，单例模式）
    private CalculationEngine() {
        initJepParsers();
    }

    /**
     * 获取计算引擎单例实例
     */
    public static CalculationEngine getInstance() {
        if (instance == null) {
            instance = new CalculationEngine();
        }
        return instance;
    }

    /**
     * 初始化JEP解析器
     */
    private void initJepParsers() {
        // 初始化弧度模式解析器
        jepRadian = new JEP();
        jepRadian.addStandardConstants();
        jepRadian.addStandardFunctions();

        // 初始化角度模式解析器
        jepDegree = new JEP();
        jepDegree.addStandardConstants();
        jepDegree.addStandardFunctions();

        // 为两个解析器添加自定义函数
        addCustomFunctions(jepRadian, true);  // 弧度模式
        addCustomFunctions(jepDegree, false); // 角度模式
    }

    /**
     * 添加自定义函数
     */
    private void addCustomFunctions(JEP jep, boolean isRadianMode) {
        // 添加通用自定义函数
        jep.addFunction("factorial", new FactorialFunction());
        jep.addFunction("random", new RandomFunction());
        jep.addFunction("cbrt", new CubeRootFunction());

        // 根据角度/弧度模式添加三角函数
        if (isRadianMode) {
            // 弧度模式使用标准三角函数
            jep.addFunction("sin", new Sine());
            jep.addFunction("cos", new Cosine());
            jep.addFunction("tan", new Tangent());
            jep.addFunction("asin", new ArcSine());
            jep.addFunction("acos", new ArcCosine());
            jep.addFunction("atan", new ArcTangent());
        } else {
            // 角度模式使用自定义三角函数
            jep.addFunction("sin", new DegreeSine());
            jep.addFunction("cos", new DegreeCosine());
            jep.addFunction("tan", new DegreeTangent());
            jep.addFunction("asin", new DegreeArcSine());
            jep.addFunction("acos", new DegreeArcCosine());
            jep.addFunction("atan", new DegreeArcTangent());
        }
    }

    /**
     * 计算表达式（默认弧度模式）
     */
    public double evaluateExpression(String expression) throws Exception {
        return evaluateExpression(expression, true);
    }

    /**
     * 计算表达式
     *
     * @param expression   要计算的表达式
     * @param isRadianMode 是否为弧度模式
     * @return 计算结果
     * @throws Exception 计算错误时抛出异常
     */
    public double evaluateExpression(String expression, boolean isRadianMode) throws Exception {
        if (expression == null || expression.trim().isEmpty()) {
            throw new Exception("表达式不能为空");
        }

        try {
            // 预处理表达式
            String processedExpr = preprocessExpression(expression);

            // 选择合适的解析器
            JEP jep = isRadianMode ? jepRadian : jepDegree;

            // 解析并计算表达式
            jep.parseExpression(processedExpr);

            if (jep.hasError()) {
                throw new Exception("解析错误: " + jep.getErrorInfo());
            }

            double result = jep.getValue();

            // 检查计算结果有效性
            if (Double.isNaN(result)) {
                throw new Exception("计算结果为NaN");
            }

            if (Double.isInfinite(result)) {
                throw new Exception("计算结果为无穷大");
            }

            return result;

        } catch (Exception e) {
            Log.e(TAG, "计算错误: " + e.getMessage(), e);
            throw e; // 重新抛出异常让调用方处理
        }
    }

    /**
     * 预处理表达式，将显示符号转换为计算符号
     */
    private String preprocessExpression(String expr) {
        // 替换显示符号为计算符号
        expr = expr.replace("×", "*");
        expr = expr.replace("÷", "/");
        expr = expr.replace("π", "pi");

        // 处理百分号
        expr = expr.replace("%", "/100");
        
        // 处理特殊情况
        expr = expr.replace("--", "+"); // 双负号变加号
        
        return expr;
    }    /**
     * 格式化计算结果（使用默认设置）
     */
    public String formatResult(double result) {
        DecimalFormat df = new DecimalFormat("0.##########");
        return df.format(result);
    }
    
    /**
     * 格式化计算结果（使用指定小数位数）
     */
    public String formatResult(double result, int decimalPlaces) {
        // 限制小数位数范围
        decimalPlaces = Math.max(0, Math.min(15, decimalPlaces));
        
        // 构建格式化字符串
        StringBuilder pattern = new StringBuilder("0");
        if (decimalPlaces > 0) {
            pattern.append(".");
            for (int i = 0; i < decimalPlaces; i++) {
                pattern.append("#");
            }
        }
        
        DecimalFormat df = new DecimalFormat(pattern.toString());
        return df.format(result);
    }

    /**
     * 检查表达式是否有效
     */
    public boolean isValidExpression(String expression) {
        try {
            evaluateExpression(expression);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    // 自定义函数实现类

    /**
     * 阶乘函数实现
     */
    private static class FactorialFunction extends PostfixMathCommand {
        public FactorialFunction() {
            numberOfParameters = 1;
        }

        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (!(param instanceof Number)) {
                try {
                    throw new Exception("阶乘函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            double value = ((Number) param).doubleValue();

            if (value < 0) {
                try {
                    throw new Exception("阶乘不能用于负数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (Math.floor(value) != value) {
                try {
                    throw new Exception("阶乘只能用于整数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            int n = (int) value;
            if (n > 170) {
                try {
                    throw new Exception("数值过大，无法计算阶乘");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            double result = 1;
            for (int i = 2; i <= n; i++) {
                result *= i;
            }

            stack.push(result);
        }
    }

    /**
     * 随机数函数实现
     */
    private static class RandomFunction extends PostfixMathCommand {
        private final Random random = new Random();

        public RandomFunction() {
            numberOfParameters = 0;
        }

        @Override
        public void run(Stack stack) {
            stack.push(random.nextDouble());
        }
    }

    /**
     * 立方根函数实现
     */
    private static class CubeRootFunction extends PostfixMathCommand {
        public CubeRootFunction() {
            numberOfParameters = 1;
        }

        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (param instanceof Number) {
                double value = ((Number) param).doubleValue();
                stack.push(Math.cbrt(value));
            } else {
                try {
                    throw new Exception("立方根函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 角度模式三角函数实现
    private static class DegreeSine extends Sine {
        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (param instanceof Number) {
                double degrees = ((Number) param).doubleValue();
                double radians = Math.toRadians(degrees);
                stack.push(Math.sin(radians));
            } else {
                try {
                    throw new Exception("正弦函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class DegreeCosine extends Cosine {
        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (param instanceof Number) {
                double degrees = ((Number) param).doubleValue();
                double radians = Math.toRadians(degrees);
                stack.push(Math.cos(radians));
            } else {
                try {
                    throw new Exception("余弦函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class DegreeTangent extends Tangent {
        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (param instanceof Number) {
                double degrees = ((Number) param).doubleValue();
                double radians = Math.toRadians(degrees);
                stack.push(Math.tan(radians));
            } else {
                try {
                    throw new Exception("正切函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class DegreeArcSine extends ArcSine {
        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (param instanceof Number) {
                double value = ((Number) param).doubleValue();
                double radians = Math.asin(value);
                stack.push(Math.toDegrees(radians));
            } else {
                try {
                    throw new Exception("反正弦函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class DegreeArcCosine extends ArcCosine {
        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (param instanceof Number) {
                double value = ((Number) param).doubleValue();
                double radians = Math.acos(value);
                stack.push(Math.toDegrees(radians));
            } else {
                try {
                    throw new Exception("反余弦函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class DegreeArcTangent extends ArcTangent {
        @Override
        public void run(Stack stack) {
            Object param = stack.pop();
            if (param instanceof Number) {
                double value = ((Number) param).doubleValue();
                double radians = Math.atan(value);
                stack.push(Math.toDegrees(radians));
            } else {
                try {
                    throw new Exception("反正切函数需要数值参数");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
